Routingの基本 – Ember.js入門(2)
Ember.jsを学ぶシリーズの2回目は、Ember.jsの特徴のひとつであるRoutingの基礎です。
なんか、気付いたらRC8がリリースされています。今度は最終RCという噂もありますが、とてもRCとは思えない変更っぷりなので、二桁くらいは確実じゃないですかね・・・(しろめ
画面遷移とHTTPリクエスト
単一の画面で構成されているシンプルなアプリケーションで無い限り、アプリケーションは複数の画面で構成されます。Webアプリケーションでは、原則として、画面を切り替える時にサーバへのリクエストを行い、画面全体を再レンダリングします。しかし、そのような仕組みでは無駄に多くの情報をサーバとやりとりする必要があります。また、ブラウザでも再レンダリングのラグが発生します。さらに、ブラウザ単体では次の画面へデータを引き継ぐことが困難です。
Ember.jsを使うと、画面の一部を書き換えることで画面遷移を実現出来ます。ページ全体を切り替えるのでは無いため、新しいデータが不要であれば、サーバへのHTTPリクエストは発生しません。ブラウザ内の処理だけで済むため、ユーザの操作感覚もネイティブアプリケーションに近くなります。
これまでも、AJaxなどの仕組みを使って、ページの一部のみを書き換える手法は実装されてきています。しかし、それらの手法は、あくまでHTMLをJavaScriptで書き換えるという考え方です。Ember.jsでは、それぞれの画面を遷移するという、本来のGUIアプリケーションの考え方でアプリケーションを設計できます。
Routingとは?
Ember.jsで画面遷移の基礎となるのがRoutingです。Routingとは、指定されたURLがどの処理を行うかを制御する仕組みです。Webアプリケーションのフレームワークを使った事があるならば、Routingと聞くとなんとなく想像できるかと思います。Ember.jsのRoutingは、それをクライアントサイドで実現するものと考えれば概ね間違っていません。
Routingでは、サーバやデプロイ環境で変わる可能性のあるURL(http://servename/appname/など)より下のパスを扱います。このパスを定義から検索し、対応する処理を行うように制御します。
Ember.jsのRouting
とりあえず、サンプルコードをみてみましょう。次のサンプルコードは、2つの画面を持つシンプルなアプリケーションです。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Routingの基本 - Ember.js</title> </head> <body> <script type="text/x-handlebars" data-template-name="index"> <h1>Index</h1> <ul> <li>{{#linkTo 'aboutme'}}About me{{/linkTo}}</li> </ul> </script> <script type="text/x-handlebars" data-template-name="aboutme"> <h1>About me</h1> <ul> <li>{{#linkTo 'index'}}Index{{/linkTo}}</li> </ul> </script> <script type="text/javascript" src="js/libs/jquery-1.9.1.js"></script> <script type="text/javascript" src="js/libs/handlebars-1.0.0.js"></script> <script type="text/javascript" src="js/libs/ember-1.0.0-rc.8.js"></script> <script type="text/javascript"> window.App = Ember.Application.create(); App.Router.map(function() { this.route("aboutme"); }); </script> </body> </html>
このコードを解説しながら、Ember.jsのRoutingを理解していきましょう。
Template
複数の画面でEmber.jsのアプリケーションを構成する場合、handlebarで画面数のTemplateを定義します。サンプルコードでは、indexとaboutmeという名前でTemplateを定義しています。Template名は、data-template-name属性で定義します。
<script type="text/x-handlebars" data-template-name="index"> <!-- ここにTemplateを記述 --> </script> <script type="text/x-handlebars" data-template-name="aboutme"> <!-- ここにTempalteを記述 --> </script>
最初に表示される画面のTemplateの名前はindexです。ただし、data-template-nameが未定義のTemplateが存在するとそちらが優先されます(アプリケーション全体でメイン画面が1つのアプリケーションとなる)。この辺りの挙動は、いわゆる命名規約の功罪ですので、そういう文化ということで諦めてください(自分は明示的に宣言する方が好きです、というか行き過ぎた命名規約は嫌い)。
画面を増やしたければ、それぞれ名前をつけて増やす事ができます。
linkTo
Templateの中で表れている{{#linkTo PATH}}NAME{{/linkTo}}は、それぞれの画面へ遷移するためのリンクです。これは、Ember.jsのComponentを利用しています。ComponentはTemplateの一種なのです。ここでは、再利用できるような小さなTemplateと考えてください。
<li>{{#linkTo 'aboutme'}}About me{{/linkTo}}</li>
ComponentのlinkToは、名前から期待できるように、ハイパーリンクを追加します。ここで指定する名前は、Routingで管理している名前です。今回はTemplate名と関連付いているので、そのままTemplateの名前と同じです。なお、Componentには独自のclassなどを指定することもできますが、解説は後日としましょう。
Routerの設定
2画面分のTemplateを定義し、それぞれに画面遷移のためのリンクを設置しましたが、アプリケーションを動作させるためには、RouterにRoutingの設定を行わなければなりません。
window.App = Ember.Application.create(); App.Router.map(function() { this.route("aboutme"); });
1行目は、前回も解説した名前空間の作成とアプリケーションの初期化です。
アプリケーションを初期化すると、その名前空間にRouterオブジェクトが作成されます。このRouterオブジェクトにアプリケーションのRoutingを設定します。ここでは、aboutmeというパスを追加しています。
画面遷移とURL
実際にコードを実行してみると、はじめにindex画面が表示され、リンクをクリックすることでAboutme画面に切り替わります。さらにリンクをクリックするとIndex画面に切り替わります。この時、サーバとの通信は発生せずに、ブラウザ内でDOMの置き換えが行われています。
まとめると次のようなイメージです。
それぞれの画面を表示した時のURLは次のようになります。
- file:///APPLICATION_ROOT/routing-basic.html#/
- file:///APPLICATION_ROOT/routing-basic.html#/aboutme
Ember.jsではアプリケーションをダウンロードするURLがベースとなるURLとなります。例えば、file:///APPLICATION_ROOT/routing-basic.htmlといったURLがベースURLです(動的ファイルであれば、http://HOST_NAME/appとかhttp://HOST_NAME/app.phpとなるでしょう)。
Ember.jsでは、このベースURLの下にパスを追加することで、各画面のURLとしています。そして、省略されている場合はindexという名前になります。
パーマリンク
Ember.jsの特徴として、アプリケーションの画面遷移を行った場合にブラウザ上のリンクも追従していくため、URLをパーマリンクとして利用できることがあげられます。すなわち、メールやSNSなどでリンクを通知すれば、相手は送信者の期待した画面を開くことが可能ということです。これは、Flashなどのアプリケーションではアプリケーションの存在するURLは伝えることができても、そのアプリケーションの状態を伝えることは難しかったため、ひとつの大きなメリットと考えて良いでしょう。
アプリケーションに複数の画面を持たせるべきか?
最後に設計について考えておきます。
Ember.jsのRoutingの仕組みは強力です。これまで全ての画面を別のページとして設計し、クライアントとサーバの間に強力な関係を作らなければならなかったWebアプリケーションの設計を、サーバは永続化データの管理、画面遷移などはすべてクライアントで行うといった設計にすることも可能です。
しかしながら、すべての画面のTemplateを最初にダウンロードするならば、初期ページが相当重くなるでしょう。また、利用しない画面のTemplateもダウンロードすることになります。
自分としては、ある程度の機能的にまとまった単位でアプリケーションとして構成した方がすっきりするのではないかと考えています。例えば、ショッピングサイトであれば、明細を表示したりといったサブ機能的な画面は、Ember.jsの画面遷移を使うべきですが、カートから決済までの流れはアプリケーションとして分割するといった感じです。この辺りの感覚は、実戦感覚がついてきたら書いてきたいトピックですね。
というわけで、今回はEmber.jsの特徴のひとつである、クライアントサイドでのRoutingについて基本的な概念を解説しました。まだまだ、まったくMVCの概念は出てきませんが、末永くお付き合いください。